// Copyright (c) 2010, Anthony Cassidy
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without modification, are 
// permitted provided that the following conditions are met:
// 
//     * Redistributions of source code must retain the above copyright notice, this list 
//         of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright notice, this 
//         list of conditions and the following disclaimer in the documentation and/or 
//         other materials provided with the distribution.
//     * Neither the name of the AntsAdventureGameCreator nor the names of its contributors 
//         may be used to endorse or promote products derived from this software without 
//         specific prior written permission.
// 
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
// THE POSSIBILITY OF SUCH DAMAGE.
#include "XStdafx.h"
#include "RoomObject.h"
#include "XRoomObject.h"
#include "XReceiver.h"
#include "XEmitter.h"
#include "Animation.h"
#include "RoomRegistry.h"
#include "Choices.h"
#include "XGlobals.h"
#include "AntsApi_NoDependencies.h"
#include "XNewEmitter.h"

/*! @cond */

#include "XDiagnostics.h"


RoomObject::RoomObject(QPointer<XRoomObject>& copyMe)
        : m_emitter( XNewEmitter(copyMe) ) // reference
        , m_orig(copyMe) // const aggregate
        , m_animCollection( copyMe->Animations()) // non-const aggregate
{
}

RoomObject::RoomObject()
        : m_emitter(XNewEmitter())
{
}

RoomObject::~RoomObject()
{
    XDiagnostics::Delete("RoomObject");
}

void RoomObject::SetTalkingAnimationName(QString animationKeyword) const
{
    m_emitter->SetTalkingAnimationName(animationKeyword);
}


void RoomObject::SetVisible(bool visible) const
{
    m_emitter->SetVisible(visible);
}

void RoomObject::PlayAnimation(QString animationKeyword, int delay) const
{
    if(animationKeyword=="")
    {
        ASSERT(false && "cannot cal with blank animation");
        return;
    }

    m_emitter->SetBlocking(true);
    m_emitter->PlayAnimation(animationKeyword, delay);
    XGlobals::DoWhileLoopWhileEmitterIsBlocking(m_emitter);
}

void ThrowExceptionIfAnimationNameIsBlank(QString name)
{
    ASSERT(name!="" && "cannot call with blank animation");
    if(name=="")
    {
        throw "cannot call with blank animation";
    }
}

void RoomObject::PlayAnimationHoldLastFrame(QString animationKeyword, int delay) const
{
    ThrowExceptionIfAnimationNameIsBlank(animationKeyword);


    m_emitter->SetBlocking(true);
    m_emitter->PlayAnimationHoldLastFrame(animationKeyword, delay);
    XGlobals::DoWhileLoopWhileEmitterIsBlocking(m_emitter);
}

void RoomObject::PlayAnimationHoldLastFrameNonBlocking(QString animationKeyword, int delay) const
{
    ThrowExceptionIfAnimationNameIsBlank(animationKeyword);

    m_emitter->PlayAnimationHoldLastFrame(animationKeyword, delay);
}


void RoomObject::PlayAnimationRepeatWhilstVisible(QString animationKeyword, int delay) const
{
    ThrowExceptionIfAnimationNameIsBlank(animationKeyword);

    m_emitter->PlayAnimationHoldLastFrame(animationKeyword, delay);
}

void RoomObject::PlayAnimationWithoutBlocking(QString animationKeyword, int delay) const
{
    ThrowExceptionIfAnimationNameIsBlank(animationKeyword);

    m_emitter->PlayAnimation(animationKeyword, delay);
}


void RoomObject::Say(QString speech) const
{
    // fire off speech whilst talking
    m_emitter->SetBlocking(true);
    m_emitter->Say(speech);

    // only difference with blocking animation is that we wait here
    XGlobals::DoWhileLoopWhileEmitterIsBlocking(m_emitter);
}

void RoomObject::SayNonBlocking(QString speech) const
{
    // fire off speech whilst talking
    m_emitter->Say(speech);
}

void RoomObject::SayWithoutAnimationNonBlocking(QString speech) const
{
    m_emitter->SayWithoutAnimation(speech);
}

void RoomObject::SayWithoutAnimation(QString speech) const
{
    m_emitter->SetBlocking(true);
    m_emitter->SayWithoutAnimation(speech);

    // only difference with blocking animation is that we wait here
    XGlobals::DoWhileLoopWhileEmitterIsBlocking(m_emitter);
}


void RoomObject::SetX(int x) const
{
    m_emitter->SetX(x);
}
void RoomObject::SetY(int y) const
{
    m_emitter->SetY(y);
}

void RoomObject::SetCurrentAnimationFrameIndex(int i) const
{
    m_emitter->SetCurrentAnimationFrameIndex(i);
}

int RoomObject::GetCurrentAnimationFrameIndex() const
{
    return m_orig->GetCurrentAnimationFrameIndex();
}

void RoomObject::SetCurrentAnimationName(QString anim) const
{
    m_emitter->SetCurrentAnimationName(anim);
}

/*!
This name is shown in the CommandLine when the mouse hovers over any pixels that belong to the RoomObject.
*/
void RoomObject::SetDisplayName(QString displayName) const
{
    m_emitter->SetDisplayName(displayName);
}

void RoomObject::PreloadAnimation(QString animKeyword) const
{
    m_emitter->PreloadAnimation(animKeyword);
}

int RoomObject::X() const
{ 

    //TODO: synch
    return m_orig->X(); 
}

int RoomObject::Y() const
{ 
    //TODO: synch
    return m_orig->Y();
}

void RoomObject::IncrementFrame() const
{
    m_emitter->IncrementFrame();
}

void RoomObject::SetTalkingDelay(int i) const
{
    m_emitter->SetTalkingDelay(i);
}

void RoomObject::UpdateImage() const
{
    m_emitter->UpdateImage();
}

void RoomObject::PlayAnimationBackwards(QString animKeyword, int delay) const
{
    m_emitter->PlayAnimationBackwards(animKeyword,delay);
}

void RoomObject::PlayAnimationBackwardsHoldLastFrame(QString animKeyword, int delay) const
{
    m_emitter->PlayAnimationBackwardsHoldLastFrame(animKeyword,delay);
    XGlobals::DoWhileLoopWhileEmitterIsBlocking(m_emitter);
}

void RoomObject::WalkTo(int x, int y) const
{
    m_emitter->WalkTo( x, y);
}

void RoomObject::SetSpecialAnimation(SpecialAnimation key, QString animKeyword) const
{
    m_emitter->SetSpecialAnimation(key, animKeyword);
}

void RoomObject::SetTalkingColor(QString color) const
{
    m_emitter->SetTalkingColor(color);
}

bool RoomObject::IsVisible() const
{
    return m_orig->IsVisible();
}

const Animations& RoomObject::GetAnimations() const
{
    return m_animCollection;
}

int RoomObject::DoChoices(Choices ch) const
{

    m_emitter->SetBlocking(true);
    m_emitter->DoChoices(ch);
    XGlobals::DoWhileLoopWhileEmitterIsBlocking(m_emitter);

    return m_orig->GetResult();
}


QPoint RoomObject::BaseMiddle() const
{
    return m_orig->BaseMiddle();
}

void RoomObject::WalkTo(QPoint p) const
{
    WalkTo(p.x(), p.y());
}

void RoomObject::SetOrderingNumber(int orderingNumber) const
{
    m_emitter->SetOrderingNumber(orderingNumber);
}

int RoomObject::OrderingNumber() const
{
    return m_orig->OrderingNumber();
}

void RoomObject::DoSingleChoice(const char* dialog) const
{
    Choices ch;
    ch.Add(1, dialog);
    this->DoChoices(ch);
}

void RoomObject::SetEnableGive(bool isGiveEnabled) const
{
    m_emitter->SetEnableGive(isGiveEnabled);
}

QString RoomObject::Keyword() const
{
    return m_orig->Keyword();
}
/*! @endcond */
